package logic

import (
	"bookmark-web/dao"
	"bookmark-web/models"
	"bookmark-web/utils"
	"errors"

	"gorm.io/gorm"
)

// CreateBookmark 创建网址收藏业务逻辑
func CreateBookmark(req *models.BookmarkCreateRequest, userID uint) (*models.BookmarkResponse, error) {
	// 1. 验证URL格式
	normalizedURL := utils.NormalizeURL(req.URL)
	if err := utils.ValidateURL(normalizedURL); err != nil {
		return nil, err
	}

	// 2. 检查URL是否已存在
	exists, err := dao.CheckBookmarkExists(normalizedURL, userID)
	if err != nil {
		return nil, errors.New("检查网址失败")
	}
	if exists {
		return nil, errors.New("该网址已存在")
	}

	// 3. 如果指定了分类，验证分类是否存在且属于当前用户
	if req.CategoryID != nil {
		_, err := dao.GetCategoryByID(*req.CategoryID, userID)
		if err != nil {
			if errors.Is(err, gorm.ErrRecordNotFound) {
				return nil, errors.New("指定的分类不存在")
			}
			return nil, errors.New("查询分类失败")
		}
	}

	// 4. 获取网址预览信息
	var title, favicon string
	if req.Title == "" {
		// 如果没有提供标题，尝试自动获取
		preview, err := utils.GetURLPreview(normalizedURL)
		if err == nil {
			title = preview.Title
			favicon = preview.Favicon
		}
	}

	// 使用提供的标题或自动获取的标题
	if req.Title != "" {
		title = req.Title
	}
	if title == "" {
		title = normalizedURL // 如果都没有，使用URL作为标题
	}

	// 5. 创建收藏对象
	bookmark := &models.Bookmark{
		Title:       title,
		URL:         normalizedURL,
		Description: req.Description,
		Favicon:     favicon,
		CategoryID:  req.CategoryID,
		UserID:      userID,
		VisitCount:  0,
	}

	// 6. 保存到数据库
	err = dao.CreateBookmark(bookmark)
	if err != nil {
		return nil, errors.New("创建收藏失败")
	}

	// 7. 重新获取收藏信息（包含关联数据）
	createdBookmark, err := dao.GetBookmarkByID(bookmark.ID, userID)
	if err != nil {
		return nil, errors.New("获取创建的收藏失败")
	}

	return createdBookmark.ToResponse(), nil
}

// GetBookmarkByID 根据ID获取收藏
func GetBookmarkByID(id uint, userID uint) (*models.BookmarkResponse, error) {
	bookmark, err := dao.GetBookmarkByID(id, userID)
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, errors.New("收藏不存在")
		}
		return nil, errors.New("查询收藏失败")
	}
	return bookmark.ToResponse(), nil
}

// GetBookmarksList 获取收藏列表（分页）
func GetBookmarksList(userID uint, req *models.BookmarkQueryRequest) (*models.BookmarkListResponse, error) {
	// 参数验证
	if req.Page <= 0 {
		req.Page = 1
	}
	if req.PageSize <= 0 {
		req.PageSize = 20
	}

	// 获取收藏列表
	bookmarks, total, err := dao.GetBookmarksByUserID(userID, req.Page, req.PageSize, req.Search, req.CategoryID)
	if err != nil {
		return nil, errors.New("获取收藏列表失败")
	}

	// 转换为响应格式
	bookmarkResponses := make([]*models.BookmarkResponse, len(bookmarks))
	for i, bookmark := range bookmarks {
		bookmarkResponses[i] = bookmark.ToResponse()
	}

	// 计算总页数
	totalPages := int(total) / req.PageSize
	if int(total)%req.PageSize > 0 {
		totalPages++
	}

	return &models.BookmarkListResponse{
		Bookmarks:  bookmarkResponses,
		Total:      total,
		Page:       req.Page,
		PageSize:   req.PageSize,
		TotalPages: totalPages,
	}, nil
}

// GetAllBookmarks 获取所有收藏（无分页）
func GetAllBookmarks(userID uint) ([]*models.BookmarkResponse, error) {
	// 获取所有收藏
	bookmarks, err := dao.GetAllBookmarksByUserID(userID)
	if err != nil {
		return nil, errors.New("获取所有收藏失败")
	}

	// 转换为响应格式
	bookmarkResponses := make([]*models.BookmarkResponse, len(bookmarks))
	for i, bookmark := range bookmarks {
		bookmarkResponses[i] = bookmark.ToResponse()
	}

	return bookmarkResponses, nil
}

// GetBookmarksByCategory 根据分类获取收藏列表
func GetBookmarksByCategory(categoryID uint, userID uint) ([]*models.BookmarkResponse, error) {
	// 验证分类是否存在且属于当前用户
	_, err := dao.GetCategoryByID(categoryID, userID)
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, errors.New("分类不存在")
		}
		return nil, errors.New("查询分类失败")
	}

	bookmarks, err := dao.GetBookmarksByCategoryID(categoryID, userID)
	if err != nil {
		return nil, errors.New("获取分类收藏失败")
	}

	// 转换为响应格式
	bookmarkResponses := make([]*models.BookmarkResponse, len(bookmarks))
	for i, bookmark := range bookmarks {
		bookmarkResponses[i] = bookmark.ToResponse()
	}

	return bookmarkResponses, nil
}

// UpdateBookmark 更新收藏
func UpdateBookmark(id uint, req *models.BookmarkUpdateRequest, userID uint) (*models.BookmarkResponse, error) {
	// 1. 获取原收藏信息
	bookmark, err := dao.GetBookmarkByID(id, userID)
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, errors.New("收藏不存在")
		}
		return nil, errors.New("查询收藏失败")
	}

	// 2. 如果更新了URL，验证格式和唯一性
	if req.URL != "" && req.URL != bookmark.URL {
		normalizedURL := utils.NormalizeURL(req.URL)
		if err := utils.ValidateURL(normalizedURL); err != nil {
			return nil, err
		}

		// 检查新URL是否已存在
		exists, err := dao.CheckBookmarkExists(normalizedURL, userID, id)
		if err != nil {
			return nil, errors.New("检查网址失败")
		}
		if exists {
			return nil, errors.New("该网址已存在")
		}

		bookmark.URL = normalizedURL
	}

	// 3. 如果指定了分类，验证分类是否存在
	if req.CategoryID != nil {
		if *req.CategoryID != 0 {
			_, err := dao.GetCategoryByID(*req.CategoryID, userID)
			if err != nil {
				if errors.Is(err, gorm.ErrRecordNotFound) {
					return nil, errors.New("指定的分类不存在")
				}
				return nil, errors.New("查询分类失败")
			}
		}
		bookmark.CategoryID = req.CategoryID
	}

	// 4. 更新其他字段
	if req.Title != "" {
		bookmark.Title = req.Title
	}
	bookmark.Description = req.Description // 允许设置为空

	// 5. 保存更新
	err = dao.UpdateBookmark(bookmark)
	if err != nil {
		return nil, errors.New("更新收藏失败")
	}

	// 6. 重新获取收藏信息
	updatedBookmark, err := dao.GetBookmarkByID(id, userID)
	if err != nil {
		return nil, errors.New("获取更新后的收藏失败")
	}

	return updatedBookmark.ToResponse(), nil
}

// DeleteBookmark 删除收藏
func DeleteBookmark(id uint, userID uint) error {
	// 1. 检查收藏是否存在
	_, err := dao.GetBookmarkByID(id, userID)
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return errors.New("收藏不存在")
		}
		return errors.New("查询收藏失败")
	}

	// 2. 删除收藏
	err = dao.DeleteBookmark(id, userID)
	if err != nil {
		return errors.New("删除收藏失败")
	}

	return nil
}

// BatchOperateBookmarks 批量操作收藏
func BatchOperateBookmarks(req *models.BookmarkBatchRequest, userID uint) error {
	// 1. 验证收藏ID列表
	if len(req.BookmarkIDs) == 0 {
		return errors.New("收藏ID列表不能为空")
	}

	// 2. 验证收藏是否都属于当前用户
	bookmarks, err := dao.GetBookmarksByIDs(req.BookmarkIDs, userID)
	if err != nil {
		return errors.New("查询收藏失败")
	}
	if len(bookmarks) != len(req.BookmarkIDs) {
		return errors.New("部分收藏不存在或无权限")
	}

	// 3. 根据操作类型执行相应操作
	switch req.Action {
	case "delete":
		err = dao.BatchDeleteBookmarks(req.BookmarkIDs, userID)
		if err != nil {
			return errors.New("批量删除失败")
		}
	case "move":
		// 如果指定了分类，验证分类是否存在
		if req.CategoryID != nil && *req.CategoryID != 0 {
			_, err := dao.GetCategoryByID(*req.CategoryID, userID)
			if err != nil {
				if errors.Is(err, gorm.ErrRecordNotFound) {
					return errors.New("目标分类不存在")
				}
				return errors.New("查询分类失败")
			}
		}

		err = dao.BatchMoveBookmarks(req.BookmarkIDs, req.CategoryID, userID)
		if err != nil {
			return errors.New("批量移动失败")
		}
	default:
		return errors.New("不支持的操作类型")
	}

	return nil
}

// GetURLPreview 获取网址预览
func GetURLPreview(url string) (*models.BookmarkPreviewResponse, error) {
	normalizedURL := utils.NormalizeURL(url)
	if err := utils.ValidateURL(normalizedURL); err != nil {
		return nil, err
	}

	preview, err := utils.GetURLPreview(normalizedURL)
	if err != nil {
		return nil, errors.New("获取网址预览失败: " + err.Error())
	}

	return preview, nil
}

// VisitBookmark 访问收藏（增加访问次数）
func VisitBookmark(id uint, userID uint) error {
	// 检查收藏是否存在
	_, err := dao.GetBookmarkByID(id, userID)
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return errors.New("收藏不存在")
		}
		return errors.New("查询收藏失败")
	}

	// 增加访问次数
	err = dao.IncrementVisitCount(id, userID)
	if err != nil {
		return errors.New("更新访问次数失败")
	}

	return nil
}
